package com.bytedesk.bytedesk_push;

import androidx.annotation.NonNull;

import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugin.common.BasicMessageChannel;
import io.flutter.plugin.common.StringCodec;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.EventChannel.StreamHandler;
import io.flutter.plugin.common.EventChannel.EventSink;

import com.xiaomi.mipush.sdk.MiPushClient;
import com.xiaomi.mipush.sdk.MiPushMessage;
import com.orhanobut.logger.Logger;
import com.orhanobut.logger.AndroidLogAdapter;

import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.Application;
import android.content.Context;
import android.os.Process;
import android.os.Handler;
import java.lang.Runnable;

import java.util.List;

/** BytedeskPushPlugin */
public class BytedeskPushPlugin implements FlutterPlugin, MethodCallHandler {
  /// The MethodChannel that will the communication between Flutter and native Android
  ///
  /// This local reference serves to register the plugin with the Flutter Engine and unregister it
  /// when the Flutter Engine is detached from the Activity
  private MethodChannel methodChannel;
  private static volatile Context context;
  private static BasicMessageChannel<String> messageChannel;
  private static EventChannel eventChannel;
  private static EventChannel.EventSink eventSink;
  public static final String MIPUSH_PLATFORM_NAME = "MIPush";

  public static Context getContext() {
    return BytedeskPushPlugin.context;
  }

  public static void setContext(Context context) {
    BytedeskPushPlugin.context = context;
  }

  @Override
  public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
    BytedeskPushPlugin.setContext(flutterPluginBinding.getApplicationContext());
    //
    methodChannel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "bytedesk_push/methodChannel");
    methodChannel.setMethodCallHandler(this);
    //
    messageChannel = new BasicMessageChannel<>(
        flutterPluginBinding.getBinaryMessenger(), "bytedesk_push/messageChannel",
        StringCodec.INSTANCE);
    messageChannel.setMessageHandler(new BasicMessageChannel.MessageHandler<String>() {
      @Override
      public void onMessage(String message, BasicMessageChannel.Reply<String> reply) {
        // 通过reply进行回复
        reply.reply("BasicMessageChannel收到：" + message);
      }
    });
    //
    eventChannel = new EventChannel(flutterPluginBinding.getBinaryMessenger(), "bytedesk_push/eventChannel");
    eventChannel.setStreamHandler(new StreamHandler() {
        @Override
        public void onListen(Object arguments, EventSink events) {
          eventSink = events;
        }
        @Override
        public void onCancel(Object arguments) {
          eventSink = null;
        }
      }
    );
  }

  @Override
  public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
    //
    if (call.method.equals("registerPush")) {
      Logger.addLogAdapter(new AndroidLogAdapter());
      // 注册
      String appId = call.argument("appId");
      String appKey = call.argument("appKey");
      registerPush(appId, appKey);

    } else if (call.method.equals("unRegister")) {
      //
      unRegister();

    } else if (call.method.equals("bindAlias")) {
      //
      String alias = call.argument("alias");
      bindAlias(alias);

    } else if (call.method.equals("unBindAlias")) {
      //
      String alias = call.argument("alias");
      unBindAlias(alias);

    } else if (call.method.equals("getAlias")) {
      // TODO：返回值
      List<String> aliases = getAlias();
      result.success(aliases);
    } else if (call.method.equals("addTag")) {
      //
      String tag = call.argument("tag");
      addTag(tag);

    } else if (call.method.equals("deleteTag")) {
      //
      String tag = call.argument("tag");
      deleteTag(tag);

    } else if (call.method.equals("getTags")) {
      // TODO: 返回值
      List<String> tags = getTags();
      result.success(tags);
    }
    // else if (call.method.equals("getPushToken")) {
    //   // 返回值
    //   String pushToken = getPushToken();
    //   result.success(pushToken);
    // }
    else if (call.method.equals("setUserAccount")) {
      // 设置账号
      String userAccount = call.argument("userAccount");
      setUserAccount(userAccount);

    } else if (call.method.equals("unsetUserAccount")) {
      // 取消设置账号
      String userAccount = call.argument("userAccount");
      unsetUserAccount(userAccount);

    } else if (call.method.equals("getPlatformVersion")) {
      // result.error(String errorCode, String errorMsg, Object errorDetails)
      // result.success(Object result)
      result.success("Android " + android.os.Build.VERSION.RELEASE);
    } else {
      result.notImplemented();
    }
  }

  @Override
  public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
    methodChannel.setMethodCallHandler(null);
  }

  // 发送消息给flutter
  // FIXME: flutter未收到此消息
  public static void sendMessage(MiPushMessage message) {
    // 2. 向Flutter端发送消息
    final String content = message.getContent();
    Logger.d("do send message %s", content);
    // 在Ui主进程中发送消息
    Handler mainHandler = new Handler(context.getMainLooper());
    Runnable myRunnable = new Runnable() {
      @Override 
      public void run() {
        //
        if (eventSink != null) {
          eventSink.success(content);
        } else {
          Logger.d("eventSink is null");
        }
        //
        messageChannel.send(content, new BasicMessageChannel.Reply<String>() {
          @Override
          public void reply(String reply) {
            Logger.d("收到Flutter的消息回复：" + reply);
          }
        });
      } // This is your code
    };
    mainHandler.post(myRunnable);
  }
  
  //
  public void registerPush(String appId, String appKey) {
    if (shouldInit()) {
      // Logger.d("appId %s, appKey %s", appId, appKey);
      MiPushClient.registerPush(context, appId, appKey);
    }
  }

  //
  static void unRegister() {
    MiPushClient.unregisterPush(context);
  }

  //
  static void bindAlias(String alias) {
    MiPushClient.setAlias(context, alias, null);
  }

  //
  static void unBindAlias(String alias) {
    MiPushClient.unsetAlias(context, alias, null);
  }

  //
  static List<String> getAlias() {
    return MiPushClient.getAllAlias(context);
  }

  //
  static void addTag(String tag) {
    MiPushClient.subscribe(context, tag, null);
  }

  //
  static void deleteTag(String tag) {
    MiPushClient.unsubscribe(context, tag, null);
  }

  //
  static List<String> getTags() {
    return MiPushClient.getAllTopic(context);
  }

  //
  // public String getPushToken() {
  //   return PushUtils.getPushToken(MIPUSH_PLATFORM_NAME);
  // }

  //
  public void setUserAccount(String userAccount) {
    // Logger.d("userAccount: %s", userAccount);
    MiPushClient.setUserAccount(context, userAccount, null);
  }

  //
  public void unsetUserAccount(String userAccount) {
    // Logger.d("unset userAccount: %s", userAccount);
    MiPushClient.unsetUserAccount(context, userAccount, null);
  }

  //
  private boolean shouldInit() {
    ActivityManager am = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE));
    List<RunningAppProcessInfo> processInfos = am.getRunningAppProcesses();
    String mainProcessName = context.getPackageName();
    int myPid = Process.myPid();
    for (RunningAppProcessInfo info : processInfos) {
      if (info.pid == myPid && mainProcessName.equals(info.processName)) {
        return true;
      }
    }
    return false;
  }

}
